package cd.zhixuan.utils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;

import java.lang.reflect.Type;

import cd.zhixuan.utils.callback.OnCallback;

/**
 * @author: HuZC
 * @Description:
 * @Date: 2022/1/10
 */
public class JsonTools {

    /**
     * Object转JSON字符串
     *
     * @param object          对象
     * @param builderCallback 操作{@link GsonBuilder}，返回{@link GsonBuilder}对象
     * @return JSON
     */
    @NonNull
    public static String object2Json(@Nullable Object object, @Nullable OnCallback<GsonBuilder, GsonBuilder> builderCallback) {
        try {
            if (object == null) return "";
            final GsonBuilder gsonBuilder;
            if (builderCallback == null) {
                gsonBuilder = new GsonBuilder().disableHtmlEscaping();
            } else {
                gsonBuilder = builderCallback.call(new GsonBuilder());
            }
            if (gsonBuilder == null) return "";
            Gson gson = gsonBuilder.create();
            return gson.toJson(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * JSON转对象
     *
     * @param json            JSON
     * @param clazz           类
     * @param builderCallback 操作{@link GsonBuilder}，返回{@link GsonBuilder}对象
     * @param deserializers   可自定义对象中其他参数类型的序列化
     * @param <T>             对象类型
     * @return 对象
     */
    @Nullable
    public static <T> T json2Object(@Nullable String json, @NonNull Class<T> clazz, @Nullable OnCallback<GsonBuilder, GsonBuilder> builderCallback,
                                    @Nullable TypeDeserializer<?>... deserializers) {
        try {
            if (json == null || json.length() == 0) return null;
            final GsonBuilder gsonBuilder;
            if (builderCallback == null) {
                gsonBuilder = new GsonBuilder();
            } else {
                gsonBuilder = builderCallback.call(new GsonBuilder());
            }
            if (gsonBuilder == null) return null;
            if (deserializers != null) {
                for (TypeDeserializer<?> deserializer : deserializers) {
                    gsonBuilder.registerTypeAdapter(deserializer.getType(), deserializer);
                }
            }
            Gson gson = gsonBuilder.create();
            return gson.fromJson(json, clazz);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * JSON转对象
     *
     * @param json            JSON
     * @param type            类型
     * @param builderCallback 操作{@link GsonBuilder}，返回{@link GsonBuilder}对象
     * @param deserializers   可自定义对象中其他参数类型的序列化
     * @param <T>             对象类型
     * @return 对象
     */
    @Nullable
    public static <T> T json2Object(@Nullable String json, @NonNull Type type, @Nullable OnCallback<GsonBuilder, GsonBuilder> builderCallback,
                                    @Nullable TypeDeserializer<?>... deserializers) {
        try {
            if (json == null || json.length() == 0) return null;
            final GsonBuilder gsonBuilder;
            if (builderCallback == null) {
                gsonBuilder = new GsonBuilder();
            } else {
                gsonBuilder = builderCallback.call(new GsonBuilder());
            }
            if (gsonBuilder == null) return null;
            if (deserializers != null) {
                for (TypeDeserializer<?> deserializer : deserializers) {
                    gsonBuilder.registerTypeAdapter(deserializer.getType(), deserializer);
                }
            }
            Gson gson = gsonBuilder.create();
            return gson.fromJson(json, type);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 自定义Json序列化
     *
     * @param <T> 类型
     */
    public abstract static class TypeDeserializer<T> implements JsonDeserializer<T> {
        @NonNull
        private final Type type;

        public TypeDeserializer(@NonNull Type type) {
            this.type = type;
        }

        @NonNull
        public Type getType() {
            return type;
        }
    }
}
